package com.heima.wemedia.service.impl;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.heima.common.exception.CustomException;
import com.heima.model.common.dtos.PageResponseResult;
import com.heima.model.common.dtos.ResponseResult;
import com.heima.model.common.dtos.WmNewsDto;
import com.heima.model.common.dtos.WmNewsPageReqDto;
import com.heima.model.common.enums.AppHttpCodeEnum;
import com.heima.model.common.pojos.wemedia.WmMaterial;
import com.heima.model.common.pojos.wemedia.WmNews;
import com.heima.model.common.pojos.wemedia.WmNewsMaterial;
import com.heima.utils.thread.WmThreadLocalUtil;
import com.heima.wemedia.mapper.WmMaterialMapper;
import com.heima.wemedia.mapper.WmNewsMapper;
import com.heima.wemedia.mapper.WmNewsMaterialMapper;
import com.heima.wemedia.service.WmAutoScanService;
import com.heima.wemedia.service.WmNewsService;
import com.heima.wemedia.service.WmTaskService;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

@Service
public class WmNewsServiceImpl extends ServiceImpl<WmNewsMapper, WmNews> implements WmNewsService {

    @Autowired
    private WmNewsMaterialMapper wmNewsMaterialMapper;
    @Autowired
    private WmMaterialMapper wmMaterialMapper;
    @Autowired
    private WmNewsMapper wmNewsMapper;
    @Autowired
    private WmAutoScanService wmAutoScanService;
    @Autowired
    private WmTaskService wmTaskService;
    /**
     * 查询文章内容列表
     * @param wmNewsPageReqDto
     * @return
     */
    @Override
    public ResponseResult pageQuery(WmNewsPageReqDto wmNewsPageReqDto) {
        //1.参数校验
        if (wmNewsPageReqDto == null)
            throw new CustomException(AppHttpCodeEnum.PARAM_INVALID);
        wmNewsPageReqDto.checkParam();

        //2.组装条件wrapper
        LambdaQueryWrapper<WmNews> wrapper = Wrappers.<WmNews>lambdaQuery();
        //2.1状态
        if (wmNewsPageReqDto.getStatus() != null){
            wrapper.eq(WmNews::getStatus,wmNewsPageReqDto.getStatus());
        }
        //2.2搜索关键字，模糊匹配文章标题
        if (StringUtils.isNotEmpty(wmNewsPageReqDto.getKeyword())){
            wrapper.like(WmNews::getTitle, wmNewsPageReqDto.getKeyword());
        }
        //2.3频道列表
        if (wmNewsPageReqDto.getChannelId() != null){
            wrapper.eq(WmNews::getChannelId,wmNewsPageReqDto.getChannelId());
        }
        //2.4发布日期
        if (wmNewsPageReqDto.getBeginPubDate() != null && wmNewsPageReqDto.getEndPubDate() != null){
            wrapper.between(WmNews::getPublishTime, wmNewsPageReqDto.getBeginPubDate(),wmNewsPageReqDto.getEndPubDate());
        }
        //2.5按创建时间倒序排序
        wrapper.orderByDesc(WmNews::getCreatedTime);

        //3.构建分页page
        Page<WmNews> page = new Page<>(wmNewsPageReqDto.getPage(), wmNewsPageReqDto.getSize());
        //4.进行分页条件查询
        page(page,wrapper);
        //5.封装结果返回
        PageResponseResult pageResponseResult = new PageResponseResult((int)page.getCurrent(),(int)page.getSize(),(int)page.getTotal());
        pageResponseResult.setData(page.getRecords());
        return pageResponseResult;
    }

    /**
     * 发布文章
     * @param wmNewsDto
     * @return
     */
    @Override
    public ResponseResult submit(WmNewsDto wmNewsDto) {

        //0.参数校验
        if (wmNewsDto == null || StringUtils.isEmpty(wmNewsDto.getTitle()) || StringUtils.isEmpty(wmNewsDto.getContent()))
            throw new CustomException(AppHttpCodeEnum.PARAM_INVALID);
        //1.新增或修改文章信息:wm_news
        //1.1创建一个实体对象：wmNews
        WmNews news = new WmNews();
        BeanUtils.copyProperties(wmNewsDto,news);
        //1.2处理文章布局为自动的情况
        if (wmNewsDto.getType() == -1){
            news.setType(null);
        }
        //1.3处理封面图片
        if (wmNewsDto.getImages() != null && wmNewsDto.getImages().size() > 0){
            String images = StringUtils.join(wmNewsDto.getImages(), ",");
            news.setImages(images);
        }
        //1.4新增或修改文章信息
        saveOrUpdateNews(news);
        //2.判断本次操作是否为草稿:草稿则结束流程
        if (wmNewsDto.getStatus() == 0)
            return ResponseResult.okResult(AppHttpCodeEnum.SUCCESS);
        //文章与素材的关联关系表:wm_news_material
        //3.提取文章内容中的素材图片，并维护内容图片与素材表的关联关系
        //3.1 解析文章内容，提取出内容图片url
       List<String> imgsInContent = getImgInContent(wmNewsDto.getContent());
        //3.2 记录文章与素材的关联关系:素材为内容引用
        saveRelationWithContentImg(imgsInContent,news);
        //4.维护封面图片与素材表的关联关系
        saveRelationWithCoverImg(imgsInContent,wmNewsDto,news);

        //开启文章的自动审核流程
        wmAutoScanService.autoScan(news.getId());
        //异步调用添加任务功能：添加一个审核文章的任务
        wmTaskService.addTask(news);

        return ResponseResult.okResult(AppHttpCodeEnum.SUCCESS);
    }

    /**
     * 保存封面图片与文章的关联关系
     * 核心职责：
     * 1.适配封面图片布局自动的情况:
     * 当内容图片数量>=1&&<3，封面布局适配 单图
     * 当内容图片数量>=3，封面布局适配三图
     * 当内容图片数量 ==0，封面布局适配 无图
     *
     * 2.保存封面图片与文章的关联关系
     * @param imgsInContent  内容图片
     * @param wmNewsDto   包含了封面图片
     * @param news   文章
     */
    private void saveRelationWithCoverImg(List<String> imgsInContent, WmNewsDto wmNewsDto, WmNews news) {
        List<String> images = wmNewsDto.getImages();
        //1.处理封面为自动的情况
        if (wmNewsDto.getType() == -1){
            //开启自动适配规则
            if (imgsInContent != null && imgsInContent.size() >= 1 && imgsInContent.size() < 3){
                //单图：截取内容图片的第一张作为封面图片
              images = imgsInContent.stream().limit(1).collect(Collectors.toList());
                news.setType((short)1);
            }else if (imgsInContent != null && imgsInContent.size() >= 3){
                //多图：截取内容图片的前三张作为封面图片
                images = imgsInContent.stream().limit(3).collect(Collectors.toList());
                news.setType((short)3);
            }else if (imgsInContent == null || images.size() == 0){
                //无图
                news.setType((short)0);
            }

            //更新文章信息
            if (images != null && images.size() > 0){
                news.setImages(StringUtils.join(images, ","));
            }
            updateById(news);
        }
        //2.保存封面图片与文章的关联关系
        if (images != null && images.size() > 0){
            saveRelationWithImg(images,news,1);
        }
    }

    //保存文章内容图片与文章的关联关系
    private void saveRelationWithContentImg(List<String> imgsInContent, WmNews news) {
        saveRelationWithImg(imgsInContent,news, 0); //0:内容引用
    }


    /**
     * 保存文章与素材图片的关联关系
     * @param imgsInContent
     * @param wmNews
     * @param type  0：内容引用  1：封面引用
     */
    private void saveRelationWithImg(List<String> imgsInContent, WmNews wmNews, int type) {
        if(imgsInContent!=null && imgsInContent.size() > 0){
            //通过图片的url查询素材的id  select * from wm_material where url in(???)
            List<WmMaterial> list = wmMaterialMapper.selectList(Wrappers.<WmMaterial>lambdaQuery()
                    .in(WmMaterial::getUrl, imgsInContent));
            List<Integer> materIalIds = list.stream().map(WmMaterial::getId).distinct().collect(Collectors.toList());

            //2.保存素材与文章的关联关系
            wmNewsMaterialMapper.saveRelations(materIalIds, wmNews.getId(), (short)type);

        }
    }

    //提取文章内容中的图片
    private List<String> getImgInContent(String content) {
        JSONArray jsonArray = JSONArray.parseArray(content);
        List<String> urls = new ArrayList<>();

        for (Object obj : jsonArray) {
            JSONObject jsonObject = JSONObject.parseObject(obj.toString());
            if ("image".equals(jsonObject.getString("type"))){
                String imgUrl = jsonObject.getString("value");
                urls.add(imgUrl);
            }
        }

        return urls;
    }

    //新增或修改文章信息
    private void saveOrUpdateNews(WmNews news) {
        if (news.getId() == null){
            //新增
            //设置用户作者id
            Integer userId = WmThreadLocalUtil.get();
            if (userId == null)
                throw new CustomException(AppHttpCodeEnum.NEED_LOGIN);
            news.setUserId(userId);
            //给定创建时间和默认状态为上架
            news.setCreatedTime(new Date());
            news.setEnable((short) 1);
            save(news);
        }else {
            //修改:先清除文章与原有的素材的关联关系
            //delete from wm news material where news_id =?
            wmNewsMaterialMapper.delete(Wrappers.<WmNewsMaterial>lambdaQuery().eq(WmNewsMaterial::getNewsId, news.getId()));
            //然后再修改当前文章信息
            updateById(news);

        }
    }

    /**
     * 根据id查询详情
     * @param id
     * @return
     */
    @Override
    public ResponseResult selectById(Integer id) {
      WmNews wmNews =  wmNewsMapper.selectById(id);
        return ResponseResult.okResult(wmNews);
    }

    /**
     * 文章上下架
     * @param
     * @return
     */
    @Override
    public ResponseResult downOrUp(Integer id) {
        if (id == null)
            throw new CustomException(AppHttpCodeEnum.PARAM_INVALID);
        WmNews wmNews = getById(id);
        if ( wmNews.getEnable() == 0){
            wmNews.setEnable((short)1);
        }else {wmNews.setEnable((short)0);}
        updateById(wmNews);
        return ResponseResult.okResult(wmNews);
    }

    /**
     * 删除文章
     * @param id
     */
    @Override
    public void delete(Integer id) {
        if (id == null)
            throw new CustomException(AppHttpCodeEnum.PARAM_INVALID);
        //删除文章与素材关联关系
        wmNewsMaterialMapper.delete(Wrappers.<WmNewsMaterial>lambdaQuery().eq(WmNewsMaterial::getNewsId,id));

        //删除文章
        wmNewsMapper.delete(Wrappers.<WmNews>lambdaQuery().eq(WmNews::getId,id));
    }
}
